/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Simulator;
/**
 * The Soper class is called directly from the Control class and will process all SOPER operations.
 * @author khhill
 */
public class Soper {
    
    
       /**
* The Add function will be called when the function bits are 000.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, adds the operand nnn amount of times, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
     * 173 - Operation exceeded bounds of memory.  Last valid value replaced on stack<br>
     * 172 - Number of desired SOPER operations > data stack length.  Operation not completed.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation. 2000 is returned if the operatiou cannot be completed.
*/
    private static int Add(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);        
        
        if(Stack.data_stack_size < operand){
            System.out.println("Error 172: Number of desired SOPER operations > data stack length.  Operation not completed.");
           return_value = 2000;
           return return_value;
        }
        
        if(operand == 0){
            return return_value;
        }
        
        int result = 0;
        int top_of_stack = 0;
        while(operand >0){
            top_of_stack = Stack.PopData();
            result = result + top_of_stack;
            if(result > 65535 || result < -65536){
                System.out.println("Error 173:  Operation exceeded bounds of memory.  Operation halted; last valid stack value replaced.");
                result = result - top_of_stack;
                return_value = 1000;
                operand = 1; // to break the loop
            }
            operand --;
        }
        
        
        
        Stack.PushData(result);
        return return_value;
    }
    
        /**
* The Sub function will be called when the function bits are 001.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, subtracts the operand nnn amount of times, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
     * 173 - Operation exceeded bounds of memory.  Last valid value replaced on stack<br>
     * 172 - Number of desired SOPER operations > data stack length.  Operation not completed.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation. 2000 is returned if the operation cannot be completed.
*/
    private static int Sub(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        
        
        if(Stack.data_stack_size < operand){
            System.out.println("Error 172: Number of desired SOPER operations > data stack length.  Operation not completed.");
           return_value = 2000;
           return return_value;
        }
        
        if(operand == 0){
            return return_value;
        }
        
        int top_of_stack = Stack.PopData();
        int result = top_of_stack;
        while(operand >1){
            top_of_stack = Stack.PopData();
            result =  result - top_of_stack;
            if(result > 65535 || result < -65536){
                System.out.println("Error 173:  Operation exceeded bounds of memory.  Operation halted; last valid stack value replaced.");
                result = result + top_of_stack;
                return_value = 1000;
                operand = 1; // to break the loop
            }
            operand --;
        }
        
        
        
        Stack.PushData(result);
        return return_value;
    }
    
    
       /**
* The Mut function will be called when the function bits are 001.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, multiplies the operand nnn amount of times, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
     * 173 - Operation exceeded bounds of memory.  Last valid value replaced on stack<br>
     * 172 - Number of desired SOPER operations > data stack length.  Operation not completed.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation. 2000 is returned if the operation cannot be completed.
*/
    private static int Mut(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        
        if(Stack.data_stack_size < operand){
            System.out.println("Error 172: Number of desired SOPER operations > data stack length.  Operation not completed.");
           return_value = 2000;
           return return_value;
        }
        
        if(operand == 0){
            return return_value;
        }
        
        int top_of_stack = Stack.PopData();
        int result = top_of_stack;
        while(operand >1){
            top_of_stack = Stack.PopData();
            result =  result * top_of_stack;
            if(result > 65535 || result < -65536){
                System.out.println("Error 173:  Operation exceeded bounds of memory.  Operation halted; last valid stack value replaced.");
                result = result / top_of_stack;
                return_value = 1000;
                operand = 1; // to break the loop
            }
            operand --;
        }
        Stack.PushData(result);
        return return_value;
    }
    
       /**
* The Div function will be called when the function bits are 001.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, divides the operand nnn amount of times, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
     * 173 - Operation exceeded bounds of memory.  Last valid value replaced on stack<br>
     * 172 - Number of desired SOPER operations > data stack length.  Operation not completed.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation. 2000 is returned if the operation cannot be completed.
*/
    private static int Div(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        
        if(Stack.data_stack_size < operand){
            System.out.println("Error 172: Number of desired SOPER operations > data stack length.  Operation not completed.");
           return_value = 2000;
           return return_value;
        }
        
        if(operand == 0){
            return return_value;
        }
        
        int top_of_stack = Stack.PopData();
        int result = top_of_stack;
        while(operand >1){
            top_of_stack = Stack.PopData();
            if(top_of_stack == 0){
                System.out.println("Error 171: Divide by 0.  Entire operation not completed");
            }
            else{ 
                result =  result / top_of_stack;
                if(result > 65535 || result < -65536){
                    System.out.println("Error 173:  Operation exceeded bounds of memory.  Operation halted; last valid stack value replaced.");
                    result = result * top_of_stack;
                    return_value = 1000;
                    operand = 1; // to break the loop
                }
            }
            operand --;
        }
        Stack.PushData(result);
        return return_value;
    }    
        /**
* The Or function will be called when the function bits are 100.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, or the operand nnn times, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* None <br>
* <p>
* <b>Date of module being installed:</b> 5/21/85
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.
*/       
    private static int Or(String bit_code,String lit_flag){
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);

        
        int top_of_stack = Stack.PopData();
        String stop_of_stack = String.valueOf(top_of_stack);
        stop_of_stack = convert_instance.getBitCode(stop_of_stack, 16);
        char[] result = stop_of_stack.toCharArray();
        while(operand >1){
            top_of_stack = Stack.PopData();
            stop_of_stack = String.valueOf(top_of_stack);
            stop_of_stack = convert_instance.getBitCode(stop_of_stack, 16);
            
            int counter = 0;
            while(counter <16){
                if(stop_of_stack.charAt(counter) == '1' || result[counter]=='1'){
                    result[counter] = '1';
                }
                else{
                    result[counter]='0';
                }
                counter ++;
            }
            operand --;
        }
        stop_of_stack = new String(result);
        top_of_stack = Integer.parseInt(stop_of_stack, 2);
        Stack.PushData(top_of_stack);
        
        return return_value;
    }
    
            /**
* The And function will be called when the function bits are 101.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, and the operand nnn times, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
*  None <br>
* <p>
* <b>Date of module being installed:</b> 5/21/85
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.
*/       
    private static int And(String bit_code,String lit_flag){
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);

        
        int top_of_stack = Stack.PopData();
        String stop_of_stack = String.valueOf(top_of_stack);
        stop_of_stack = convert_instance.getBitCode(stop_of_stack, 16);
        char[] result = stop_of_stack.toCharArray();
        while(operand >1){
            top_of_stack = Stack.PopData();
            stop_of_stack = String.valueOf(top_of_stack);
            stop_of_stack = convert_instance.getBitCode(stop_of_stack, 16);
            
            int counter = 0;
            while(counter <16){
                if(stop_of_stack.charAt(counter) == '1' && result[counter]=='1'){
                    result[counter] = '1';
                }
                else{
                    result[counter]='0';
                }
                counter ++;
            }
            operand --;
        }
        stop_of_stack = new String(result);
        top_of_stack = Integer.parseInt(stop_of_stack, 2);
        Stack.PushData(top_of_stack);
        
        return return_value;
    }
    
    
               /**
* The Write function will be called when the function bits are 111.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then writes nnn items from the data stack.<p>
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* None <br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
* @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors. 
*/    
    private static int Write(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
 
        if(operand > Stack.data_stack_size){
            operand = Stack.data_stack_size;
            System.out.println("Error 215: Operand > stack length. Replacing operand with stack length");
        }
        int counter = 0;
        while(counter < operand){
            System.out.println(Stack.data_stack[counter]);
            counter ++;
        }
        
        return return_value;
    }
    
                  /**
* The Read function will be called when the function bits are 110.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  It then reads the file n amount of times, as determined by the operand.<p>
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 178 - Failed to write from read file.  Invalid syntax.  Process stopped early.<br>
* 177 - Failed to read from the read file.  Read count max reached.  Line ignored<br>
* <p>
* <b>Date of module being installed:</b> 5/24/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
* @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the memory location is not defined. 5000 is returned if the destination memory is out of range
*/    
    private static int Read(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        
        while(operand>0){
        
            if(Control.read_counter >= Control.read_size){
                System.out.println("Error 177: Failed to read from the read file.  Read count max reached.  Line ignored");
                return_value = 2000;            
                return return_value;
            }
            else{
                try{            
                    return_value = Stack.PushData(Integer.parseInt(Control.read_string[Control.read_counter],16));
                    Control.read_counter++;
                }
                catch(Exception e){
                    System.out.println("Error 178: Failed to write from read file.  Invalid syntax.  Process stopped early.");            
                    return_value = 2000;
                }
                if(return_value ==2000){
                    return return_value;
                }
            }
        operand --;
        }
        
        return return_value;
    }
    
    
    
            /**
    * The Control function will recive the call from the Simulator's Control class.  It will receive the bit 
         * information.  It will start by throwing away the first two bits since they are no longer needed.  It will then 
         * check the next three bits and call the appropriate function class with the literal flag and the operand bits as 
         * parameters.
    * <p>
    * <b>Change Log:</b><br>
    * None<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * None <br>
    * <p>
    * <b>Date of module being installed:</b> 5/21/08
    * <p><b>Original Author:</b>  Keith Hill
    * @param bit_code This is the incomming bit code that will be processed.
    */
    public static void Control(String bit_code){
        bit_code = bit_code.replaceFirst("10", "");
        String function = bit_code.substring(0, 3);
        bit_code = bit_code.replaceFirst(function, "");
        String lit_flag = bit_code.substring(0,1);
        bit_code = bit_code.replaceFirst(lit_flag, "");
        
        int result = 0;
        if(function.equals("000")){
            result = Add(bit_code,lit_flag);
        }
        else if(function.equals("001")){
            result = Sub(bit_code,lit_flag);
        }
        else if(function.equals("010")){
            result = Mut(bit_code,lit_flag);
        }
        else if(function.equals("011")){
            result = Div(bit_code,lit_flag);
        }
        else if(function.equals("100")){
            result = Or(bit_code,lit_flag);
        }
        else if(function.equals("101")){
            result = And(bit_code,lit_flag);
        }
        else if(function.equals("110")){
            result = Read(bit_code,lit_flag);
        }
        else if(function.equals("111")){
            result = Write(bit_code,lit_flag);
        }
        else{
            System.out.println("How the fuck did that happen?");
        }
        
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        String status_result=convert_instance.getBitCode(String.valueOf(Control.location_counter), 10);
        if(result == 1){
            status_result =  "000000"+status_result;
        }
        else if(result == 1000){
            status_result = "110000"+status_result;
        }
        else if(result == 2000){
            status_result = "100000"+status_result;
        }
        status_result = convert_instance.binaryToHex(status_result);
        while(status_result.length()<4){
            status_result = "0" + status_result;
        }
        Stack.PushStatus(status_result);
        Control.location_counter++;
    }
}
